package alarm

import (
	"errors"
	"fmt"
	"log"
	"time"
	"xin-job/admin/dao"
	"xin-job/admin/dao/model"
	"xin-job/admin/trigger"
)

type Alarm interface {
	DoAlarm(*model.XxlJobInfo, *model.XxlJobLog) bool
}

type EmailAlarm struct{}

func (e *EmailAlarm) DoAlarm(jobInfo *model.XxlJobInfo, jobLog *model.XxlJobLog) bool {
	// TODO send email
	fmt.Println("send email")
	return true
}

func newEmailAlarm() *EmailAlarm {
	return &EmailAlarm{}
}

// JobAlarmer 任务告警组
type jobAlarmer struct {
	alarms []Alarm // 告警器
}

func newJobAlarmer() *jobAlarmer {
	i := &jobAlarmer{
		alarms: make([]Alarm, 0),
	}
	i.alarms = append(i.alarms, newEmailAlarm())
	return i
}
func (a *jobAlarmer) addAlarm(alarm any) error {
	if v, ok := alarm.(Alarm); ok {
		a.alarms = append(a.alarms, v)
		return nil
	}

	return errors.New("参数错误，未实现 Alarm 接口")
}
func (a *jobAlarmer) doAlarm(jobInfo *model.XxlJobInfo, jobLog *model.XxlJobLog) bool {
	if len(a.alarms) == 0 {
		return false
	}

	var r = true
	for _, v := range a.alarms {
		r = v.DoAlarm(jobInfo, jobLog)
	}
	return r
}

type JobFailMonitorHelper struct {
	jobAlarmer *jobAlarmer
	stopFlag   chan struct{}
}

var instance = &JobFailMonitorHelper{
	jobAlarmer: newJobAlarmer(),
	stopFlag:   make(chan struct{}),
}

func GetInstance() *JobFailMonitorHelper {
	return instance
}

func (f *JobFailMonitorHelper) AddAlarm(alarm any) error {
	return f.jobAlarmer.addAlarm(alarm)
}

func (f *JobFailMonitorHelper) Start() {
	go func() {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("send alarm err=%v\n", err)
			}
		}()

		for {

			select {
			case <-f.stopFlag:
			default:

				ids := dao.FindFailJobLogIds(1000)
				if len(ids) > 0 {
					for _, logId := range ids {
						// 告警状态：0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败
						ret := dao.UpdateAlarmStatus(logId, 0, -1)
						if ret == 0 {
							continue
						}

						jobLog := dao.LoadLog(logId)
						job := dao.LoadJobInfoById(jobLog.JobId)

						if jobLog.ExecutorFailRetryCount > 0 {
							// 重试
							trigger.AddTrigger(job.Id, "RETRY", jobLog.ExecutorFailRetryCount-1, jobLog.ExecutorShardingParam, jobLog.ExecutorParam, "")

							var retryMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试触发<<<<<<<<<<< </span><br>"
							jobLog.TriggerMsg = jobLog.TriggerMsg + retryMsg
							dao.UpdateTriggerInfo(jobLog)
						}

						newAlarmStatus := 0
						if job != nil {
							r := f.jobAlarmer.doAlarm(job, jobLog)
							if r {
								newAlarmStatus = 2
							} else {
								newAlarmStatus = 3
							}
						} else {
							newAlarmStatus = 1
						}
						dao.UpdateAlarmStatus(jobLog.Id, -1, newAlarmStatus)
					}
				}
			}
			time.Sleep(10 * time.Second)
		}
	}()
}

func (f *JobFailMonitorHelper) Stop() {
	f.stopFlag <- struct{}{}
}
